-- 运营活动: 幸运购


--[[
{
    cmd_id = 1, -- 命令id，用于批量停止、删除活动 
    act_id = 88, -- 活动id (88 幸运购)
    act_name = "幸运购", -- 活动名称
    act_desc = "每次摇奖都可获取积分，消耗积分兑换奖励！", -- 活动描述
    beg_time = 1493262000,  -- 活动开始时间(unix timestamp)
    end_time = 1593267400,  -- 活动结束时间(unix timestamp)
    config = -- 配置数据
    {
        dailyItems = 
        {
            {type = 0, id = 842, count = 1, bind = 0,},  --第一天团购物品
            {type = 0, id = 852, count = 1, bind = 0,},
            {type = 0, id = 862, count = 1, bind = 0,},
            {type = 0, id = 872, count = 1, bind = 0,},
            {type = 0, id = 1161, count = 1, bind = 0,},
            {type = 0, id = 1162, count = 1, bind = 0,},
            {type = 0, id = 1163, count = 1, bind = 0,},
            {type = 0, id = 1171, count = 1, bind = 0,},
            {type = 0, id = 1172, count = 1, bind = 0,},
            {type = 0, id = 1173, count = 1, bind = 0,},
            {type = 0, id = 1181, count = 1, bind = 0,},
            {type = 0, id = 1188, count = 1, bind = 0,},
            {type = 0, id = 1183, count = 1, bind = 0,},
            {type = 0, id = 1189, count = 1, bind = 0,},
            {type = 0, id = 841, count = 1, bind = 0,},
            {type = 0, id = 851, count = 1, bind = 0,},
            {type = 0, id = 861, count = 1, bind = 0,},
            {type = 0, id = 871, count = 1, bind = 0,},
        },
        dailySpecialItems = 
        {
            {   --第一天特殊奖励
                {type = 0, id = 842, count = 1, bind = 0,},
                {type = 0, id = 852, count = 1, bind = 0,},
                {type = 0, id = 862, count = 1, bind = 0,},
            },
        },
        buyCost = 30, --购买消耗元宝
        AwardTime = 75600, --当天第几秒的时候开奖
        LastBuyCount = 200,     --开奖最低全服购买次数
    },
}
]]

-- 检查配置是否正确，正确则返回 0，否则返回错误码
function oper_act_88_check_cfg(cfg)
    if cfg == nil then return 20 end
    
    local config = cfg.config
    if config == nil then return 21 end
    
    --[[
    if config.BossList == nil then return 23 end
    if type(config.BossList) ~= "table" then return 24 end
    for idx = 1, #config.BossList do
        local dayRewards = config.BossList[idx]
        if dayRewards == nil then return 25 end
        if type(dayRewards) ~= "table" then return 26 end
        if dayRewards.awards == nil then return 27 end
        if type(dayRewards.awards) ~= "table" then return 28 end
        if not oper_act_check_one_award_cfg(dayRewards.awards) then
            return 22
        end 
    end
    ]]

    if config.itemList == nil then return 29 end
    if type(config.itemList) ~= "table" then return 30 end
    for idx = 1, #config.itemList do
        local item = config.itemList[idx]
        if item == nil then return 31 end
        local dayRewards = item.awards
        if dayRewards == nil then return 32 end
        if type(dayRewards) ~= "table" then return 33 end
        if not oper_act_check_one_award_cfg(dayRewards) then
            return 22
        end 
    end

    return 0
end

-- 安装活动，成功则返回 0，否则返回错误码
function oper_act_88_setup(cfg) 
    return 0
end

-- 卸载活动
function oper_act_88_unsetup(cfg)   
end

-- 活动开始
function oper_act_88_start(cfg)
    local ssVar = System.getStaticVar()
    ssVar.oper_act_88_start = 1
    ssVar.oper_act_88_cmd = cfg.cmd_id
    ssVar.oper_act_88_act = cfg.act_id
    ssVar.oper_act_88_posX = nil
    ssVar.oper_act_88_posY = nil
    ssVar.oper_act_88_sceneId = nil

    if not cfg then return end
    local config = cfg.config
    if not config then return end

    local dVar = System.getDyanmicVar()
    dVar.oper_act_88_mob_idx = {}
    

    local lastTime = System.getCurrMiniTime() - System.getToday()

    local timerH = System.getTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time_delay")
    if timerH then
        System.unregisterTimeCall(timerH)
    end
    local timerH2 = System.getTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time")
    if timerH2 then
        System.unregisterTimeCall(timerH2)
    end
    local minTime,maxTime = oper_act_88_get_min_max_mob_time(config)
    local awardTime = config.every_check_time
    if minTime > lastTime then
        awardTime = minTime - lastTime
        System.registerTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time_delay", NULL, awardTime, false)
    elseif maxTime < lastTime then
        oper_act_88_check_mob_monsters(config, lastTime, true)
    else
        System.registerTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time", NULL, awardTime, false)
        oper_act_88_check_mob_monsters(config, lastTime, true)
    end

    local data = gRankMgr_GetValueByIndx(0, RANK_DEFINE_OPERATION_88, 1)

    if data then
        local myData = BaseFuc_unserialize(data)
        if myData and myData.cmd_id and myData.cmd_id == cfg.cmd_id and myData.act_id and myData.act_id == cfg.act_id and
            myData.time and cfg.beg_time <= myData.time and  cfg.end_time > myData.time then
            return
        end
    end

    gRankMgr_Clear(RANK_DEFINE_OPERATION_88)
end

-- 活动结束
function oper_act_88_end(cfg)
    local ssVar = System.getStaticVar()
    ssVar.oper_act_88_start = nil
    ssVar.oper_act_88_cmd = nil
    ssVar.oper_act_88_act = nil
    ssVar.oper_act_88_posX = nil
    ssVar.oper_act_88_posY = nil
    ssVar.oper_act_88_sceneId = nil

    if not cfg then return end
    local config = cfg.config
    if not config then return end
    local timerH = System.getTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time_delay")
    if timerH then
        System.unregisterTimeCall(timerH)
    end

    local timerH2 = System.getTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time")
    if timerH2 then
        System.unregisterTimeCall(timerH2)
    end
end

-- 打包数据
function oper_act_88_packet_data(sysarg, cfg)
    local ssVar = System.getStaticVar()
    if not ssVar.oper_act_88_start then
        return
    end
    if not cfg then
        return
    end

    local config = cfg.config
    if not config then
        return
    end

    
    local actorid = Actor.getActorId(sysarg)
    local data = gRankMgr_GetValueById(actorid, RANK_DEFINE_OPERATION_88, 1)
    local myData = BaseFuc_unserialize(data)

    if not myData or myData == "" or myData == 0 then
        myData = {}
    end

    local time = System.getSystemTime()
    if config.dailyExchange and config.dailyExchange == 1 and myData.mySelfTime and not System.isUnixTimeSameDay(myData.mySelfTime, time) then
        myData.myBuyLimit = {}
    end

    if not myData.myBuyLimit then
        myData.myBuyLimit = {}
    end

    local pack = oper_act_alloc_init_data_packet(sysarg, cfg.cmd_id, cfg.act_id)
    if (pack == nil) then
        return
    end

    local len = #config.itemList

    DataPack.writeByte(pack, len)
    for idx = 1, len do
        local item = config.itemList[idx]
        DataPack.writeByte(pack, idx)
        local num = item.limitNum - (myData.myBuyLimit[idx] or 0)
        if item.limitNum == -1 then
            num = item.limitNum
        end
        DataPack.writeShort(pack, num)
    end

    DataPack.writeShort(pack, ssVar.oper_act_88_sceneId or 0)
    DataPack.writeShort(pack, ssVar.oper_act_88_posX or 0)
    DataPack.writeShort(pack, ssVar.oper_act_88_posY or 0)

    DataPack.flush(pack)


    
end

-- 操作，返回操作结果，0为成功
function oper_act_88_do(sysarg, cfg, clientPkt)
    if cfg == nil then return end
    
    if cfg.state == nil or cfg.state ~= 1 then -- 不在活动中
        Actor.sendTipmsg(sysarg,Lang.ScriptTips.Operation001, ttFlyTip)
        return
    end
    
    local config = cfg.config
    if config == nil then -- 参数错误
        print("error, oper_act_88_do cfg.config confg error")
        return
    end

    local nIndex = DataPack.readByte( clientPkt )

    --print("nIndex ="..nIndex)
    local actorid = Actor.getActorId(sysarg)
    local data = gRankMgr_GetValueById(actorid, RANK_DEFINE_OPERATION_88, 1)

    local myData = BaseFuc_unserialize(data)
    

    if not myData or myData == "" or myData == 0 then
        myData = {}
    end

    local time = System.getSystemTime()
    if config.dailyExchange and config.dailyExchange == 1 and myData.mySelfTime and not System.isUnixTimeSameDay(myData.mySelfTime, time) then
        myData.myBuyLimit = {}
    end

    if not myData.myBuyLimit then
        myData.myBuyLimit = {}
    end

    local result = 0    

    local item = config.itemList[nIndex]

    if not item then
        Actor.sendTipmsg(sysarg,Lang.ScriptTips.Operation015, ttFlyTip)
        return
    end

    if item.limitNum ~= -1 and myData.myBuyLimit[nIndex] and item.limitNum <= myData.myBuyLimit[nIndex] then
        Actor.sendTipmsg(sysarg,Lang.ScriptTips.Operation016, ttFlyTip)
        return
    end

    if not myData.myBuyLimit[nIndex] then
        myData.myBuyLimit[nIndex] = 0
    end

    if IsBagGridEnough(sysarg, item.awards) then
       
        if not CheckConsumeCond( sysarg, item.consumes, 1 ) then
            return
        end
        if not DoConsumeCond( sysarg, item.consumes, 1, LogIds.OperationLogId088, Lang.LogTips.Operation088 ) then
            return
        end

        myData.myBuyLimit[nIndex] = myData.myBuyLimit[nIndex] + 1
        GiveCommonAward(sysarg, item.awards, LogIds.OperationLogId088, Lang.LogTips.Operation088)

        if not myData.cmd_id then
            myData.cmd_id = cfg.cmd_id
            myData.act_id = cfg.act_id
            myData.time = time
        end

        myData.mySelfTime = time

        local newData = BaseFuc_serialize(myData)

        gRankMgr_SetRankEx(actorid, RANK_DEFINE_OPERATION_88, 1, newData)


        local netPack = oper_act_alloc_do_result_packet(sysarg, cfg.cmd_id, cfg.act_id, result)
        DataPack.writeByte(netPack, nIndex)
        local lastNum = item.limitNum - myData.myBuyLimit[nIndex]
        if item.limitNum == -1 then
            lastNum = item.limitNum
        end
        DataPack.writeShort(netPack, lastNum)
        DataPack.flush(netPack)
    else
        Actor.sendTipmsg(sysarg,Lang.ScriptTips.COM0015, ttFlyTip)
        return
    end
end


-- 跨天
function oper_act_88_new_day_arrive(act_id) 
    local ssVar = System.getStaticVar()
    if not ssVar.oper_act_88_start then
        return
    end
    if not ssVar.oper_act_88_cmd then
        return
    end
    if not ssVar.oper_act_88_act then
        return
    end
    local cfg = get_oper_act_cfg(ssVar.oper_act_88_cmd, ssVar.oper_act_88_act)
    if not cfg then
        return
    end
    local config = cfg.config
    if not config then return end

    local dVar = System.getDyanmicVar()
    dVar.oper_act_88_mob_idx = {}

    local lastTime = System.getCurrMiniTime() - System.getToday()

    local timerH = System.getTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time_delay")
    if timerH then
        System.unregisterTimeCall(timerH)
    end

    local timerH2 = System.getTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time")
    if timerH2 then
        System.unregisterTimeCall(timerH2)
    end
    local minTime,maxTime = oper_act_88_get_min_max_mob_time(config)
    local awardTime = config.every_check_time
    if minTime > lastTime then
        awardTime = minTime - lastTime
        System.registerTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time_delay", NULL, awardTime, false)
    elseif maxTime < lastTime then
        oper_act_88_check_mob_monsters(config, lastTime)
    else
        System.registerTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time", NULL, awardTime, false)
        oper_act_88_check_mob_monsters(config, lastTime)
    end
    
end

function oper_act_88_every_check_time_delay()
    local timerH = System.getTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time_delay")
    if timerH then
        System.unregisterTimeCall(timerH)
    end
    local ssVar = System.getStaticVar()
    if not ssVar.oper_act_88_start then
        return
    end
    if not ssVar.oper_act_88_cmd then
        return
    end
    if not ssVar.oper_act_88_act then
        return
    end
    local cfg = get_oper_act_cfg(ssVar.oper_act_88_cmd, ssVar.oper_act_88_act)
    if not cfg then
        return
    end
    local config = cfg.config
    if not config then return end   

    local lastTime = System.getCurrMiniTime() - System.getToday()


    local minTime,maxTime = oper_act_88_get_min_max_mob_time(config)
    if lastTime < maxTime then
        System.registerTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time", NULL, config.every_check_time, false)        
    end

    oper_act_88_check_mob_monsters(config, lastTime)
    oper_act_88_packet_data(sysarg, cfg)
end

function oper_act_88_every_check_time()
    local ssVar = System.getStaticVar()
    if not ssVar.oper_act_88_start then
        return
    end
    if not ssVar.oper_act_88_cmd then
        return
    end
    if not ssVar.oper_act_88_act then
        return
    end
    local cfg = get_oper_act_cfg(ssVar.oper_act_88_cmd, ssVar.oper_act_88_act)
    if not cfg then
        return
    end
    local config = cfg.config
    if not config then return end   

    local lastTime = System.getCurrMiniTime() - System.getToday()

    local minTime,maxTime = oper_act_88_get_min_max_mob_time(config)
    if lastTime < maxTime then
        --System.registerTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time", NULL, config.every_check_time, false)
    else
        local timerH = System.getTimeCall(System.getGlobalNpc(), "oper_act_88_every_check_time")
        if timerH then
            System.unregisterTimeCall(timerH)
        end
    end

    oper_act_88_check_mob_monsters(config, lastTime)
    oper_act_88_packet_data(sysarg, cfg)
end

function oper_act_88_check_mob_monsters(config, time, noBroadCast)
    local needBroadCast = true
    if noBroadCast then
        needBroadCast = false
    end
    local dVar = System.getDyanmicVar()
    if not dVar.oper_act_88_mob_idx then
        dVar.oper_act_88_mob_idx = {}
    end
    for idx = 1, #config.BossList do
        local everyBossCfg = config.BossList[idx]
        if not dVar.oper_act_88_mob_idx[idx] then
            dVar.oper_act_88_mob_idx[idx] = 0
        end
        for ii = #everyBossCfg.mob_time_list, 1, -1 do
            local mobTime = everyBossCfg.mob_time_list[ii]
            if time >= mobTime and dVar.oper_act_88_mob_idx[idx] < ii then
                local needRefresh = false
                local isCrossServer = OnCsActorLoginLmt()
                if isCrossServer and everyBossCfg.needCross == 1 then
                    needRefresh = true
                elseif not isCrossServer and (not everyBossCfg.needCross or everyBossCfg.needCross == 0) then
                    needRefresh = true
                end
                if needRefresh then
                    --print("idx = "..idx)
                    --print("everyBossCfg.mob_time_list[ii] ="..everyBossCfg.mob_time_list[ii])
                    dVar.oper_act_88_mob_idx[idx] = ii
                    --print("ii ="..ii)
                    local nextBossBornTime = oper_act_88_get_boss_live_time(config, everyBossCfg.mob_time_list[ii])
                    --print("nextBossBornTime ="..nextBossBornTime)
                    --print("time ="..time)
                    if nextBossBornTime ~= 0 and nextBossBornTime <= time then
                        break
                    end
                    local newBossList = oper_act_88_clone_monters(everyBossCfg.boss, nextBossBornTime, mobTime, time)
                    local newMonsterList = oper_act_88_clone_monters(everyBossCfg.monsters, nextBossBornTime, mobTime, time)
                    oper_act_88_mob_monsters( newBossList, true , needBroadCast)
                    oper_act_88_mob_monsters( newMonsterList, false, needBroadCast)
                   
                end
                break
            end
        end
    end
end

function oper_act_88_clone_monters(monsters, nextBossBornTime, mobTime, time)
    local list = {}
    for i, monster in ipairs(monsters) do
        local nnLiveTime = monster.livetime
        if nextBossBornTime ~= 0 and nextBossBornTime < mobTime + monster.livetime then
            nnLiveTime = nextBossBornTime - mobTime
        end
        nnLiveTime = nnLiveTime + mobTime - time
        --print("nnLiveTime ="..nnLiveTime)
        local newMonster={}
        newMonster.monsterId               = monster.monsterId
        local sceneRanNum
        if monster.sceneList and #monster.sceneList > 0 then
            sceneRanNum = System.getRandomNumber(#monster.sceneList) + 1
            newMonster.sceneId             = monster.sceneList[sceneRanNum] or monster.sceneId
        else
            newMonster.sceneId             = monster.sceneId
        end
        newMonster.num                     = monster.num
        if monster.posList and #monster.posList > 0 then
            if sceneRanNum and type(monster.posList[sceneRanNum][1]) ~= 'number' then
                local ranNum = System.getRandomNumber(#monster.posList[sceneRanNum]) + 1
                newMonster.pos                 = monster.posList[sceneRanNum][ranNum] or monster.pos
            else
                local ranNum = System.getRandomNumber(#monster.posList) + 1
                newMonster.pos                 = monster.posList[ranNum] or monster.pos
            end
        else
            newMonster.pos                 = monster.pos
        end
        newMonster.livetime                = nnLiveTime
        newMonster.range                   = monster.range
        if nnLiveTime > 0 then
            table.insert(list, newMonster)
        end
    end
    return list
end

function oper_act_88_mob_monsters( monsterList, isBoss, needBroadCast)
    local ssVar = System.getStaticVar()
    if #monsterList > 0 then
        if isBoss then
            for idx = 1, #monsterList do
                freshSceneMonsterInPosForce(monsterList[idx])
                if needBroadCast then
                    local sceneName = ""
                    if monsterList[idx].sceneId then
                        sceneName = Fuben.getSceneNameById( monsterList[idx].sceneId )
                    end
                    local monsterName = MonsterNameDeleteNumber(monsterList[idx].monsterId)
                    System.broadcastTipmsg(string.format(Lang.ScriptTips.Operation221, monsterName, sceneName, monsterList[idx].sceneId or 0, monsterList[idx].pos[1] or 0 , monsterList[idx].pos[2] or 0),ttScreenCenter + ttChatWindow)
                    ssVar.oper_act_88_posX = monsterList[idx].pos[1]
                    ssVar.oper_act_88_posY = monsterList[idx].pos[2]
                    ssVar.oper_act_88_sceneId = monsterList[idx].sceneId
                end
            end
        else
            for idx = 1, #monsterList do
                freshSceneMonsterInRangeForce(monsterList[idx])
            end
        end
    end
end

function oper_act_88_get_min_max_mob_time(config)
    local maxTime = 0 
    local minTime = 86400
    local isCrossServer = OnCsActorLoginLmt()
    for idx = 1, #config.BossList do
        local everyBossCfg = config.BossList[idx]
        local needCalc = false
        if isCrossServer and everyBossCfg.needCross == 1 then
            needCalc = true
        elseif not isCrossServer and (not everyBossCfg.needCross or everyBossCfg.needCross == 0) then
            needCalc = true
        end
        if needCalc then
            if everyBossCfg.mob_time_list[1] < minTime then
                minTime = everyBossCfg.mob_time_list[1]
            end
            if everyBossCfg.mob_time_list[#everyBossCfg.mob_time_list] > maxTime then
                maxTime = everyBossCfg.mob_time_list[#everyBossCfg.mob_time_list]
            end
        end
    end
    --print("minTime ="..minTime)
    --print("maxTime ="..maxTime)
    return minTime, maxTime
end

function oper_act_88_get_boss_live_time(config, curTime)
    local isCrossServer = OnCsActorLoginLmt()
    local result = 90000
    for idx = 1, #config.BossList do
        local everyBossCfg = config.BossList[idx]
        local needCalc = false
        if isCrossServer and everyBossCfg.needCross == 1 then
            needCalc = true
        elseif not isCrossServer and (not everyBossCfg.needCross or everyBossCfg.needCross == 0) then
            needCalc = true
        end
        if needCalc then
            for ii = 1, #everyBossCfg.mob_time_list do
                if everyBossCfg.mob_time_list[ii] > curTime and everyBossCfg.mob_time_list[ii] < result then
                    result = everyBossCfg.mob_time_list[ii]
                end
            end
        end
    end
    if result == 90000 then
        return 0
    end
    return result
end
